﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using EFFC.Net.Interface;
using WinSCP;
using EFFC.Net.Parameters;
using EFFC.Net.Returns;
using EFFC.Net.Common;
using EFFC.Net.ResourceLib.Parameters;
using EFFC.Net.ResourceLib.Returns;

namespace EFFC.Net.ResourceLib.Communication
{
    public class SFTPAccess:IDisposable, IResourceEntity
    {
        private string _id = "";
        Session session = null;

        public string ID
        {
            get
            {
                if (_id == "")
                {
                    _id = "SFTPAccess" + Guid.NewGuid().ToString();
                }

                return _id;
            }
        }

        public void Release()
        {
            if (session != null)
            {
                session = null;
            }
        }

        public void Dispose()
        {
            session.Dispose();
        }
        /// <summary>
        /// 獲取一個默認的參數
        /// </summary>
        /// <param name="hostName">伺服器IP或URI</param>
        /// <param name="username">訪問用戶名</param>
        /// <param name="password">訪問密碼</param>
        /// <param name="sshhostkey">主机的hostkey，格式：ssh-rsa 1024 xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx</param>
        /// <returns></returns>
        public static SFTPParameter GetDefinedParameter(string hostName,string username,string password,string sshhostkey)
        {
            SFTPParameter p = new SFTPParameter();
            p.HostName = hostName;
            p.UserName = username;
            p.Password = password;
            p.SSHHostKey = sshhostkey;
            return p;
        }
        /// <summary>
        /// 根據盤符獲取驅動器遠端路徑串
        /// </summary>
        /// <param name="driver">驅動器盤符</param>
        /// <returns>string</returns>
        public static string RemoteDriverPath(string driver)
        {
            return @"/cygdrive/" + driver + @"/";
        }

        /// <summary>
        /// 上傳文件到遠端指定目錄
        /// </summary>
        /// <param name="p">SFTPParameter</param>
        /// <returns>SFTPRtn</returns>
        public SFTPRtn PutFiles(SFTPParameter p)
        {
            SFTPRtn rtn = new SFTPRtn();
            try
            {
                SessionOptions sops = InitParameter(p);
                using (Session session = new Session())
                {
                    session.ExecutablePath = string.IsNullOrEmpty(p.WinscpExePath) ? null : p.WinscpExePath;
                    // Connect
                    session.Open(sops);

                    // Upload files
                    TransferOptions transferOptions = new TransferOptions();
                    transferOptions.TransferMode = p.TransferMode;
                    TransferOperationResult transferResult;
                    transferResult = session.PutFiles(p.LocalPath, p.RemotePath, p.IsRemoveSourceFile, transferOptions);

                    // Throw on any error
                    transferResult.Check();

                    //foreach (TransferEventArgs transfer in transferResult.Transfers)
                    //{
                        
                    //}

                    rtn.IsSuccess = true;
                }
            }
            catch (Exception ex)
            {
                rtn.IsSuccess = false;
                rtn.ErrorMessage = ex.Message;
                throw ex;
            }
            return rtn;
        }
        /// <summary>
        /// 從伺服器上獲取文件到指定的本地目錄
        /// </summary>
        /// <param name="p">SFTPParameter</param>
        /// <returns>SFTPRtn</returns>
        public SFTPRtn GetFiles(SFTPParameter p)
        {
            SFTPRtn rtn = new SFTPRtn();
            try
            {
                SessionOptions sops = InitParameter(p);
                using (Session session = new Session())
                {
                    session.ExecutablePath = string.IsNullOrEmpty(p.WinscpExePath) ? null : p.WinscpExePath;
                    // Connect
                    session.Open(sops);

                    // Upload files
                    TransferOptions transferOptions = new TransferOptions();
                    transferOptions.TransferMode = p.TransferMode;
                    TransferOperationResult transferResult;
                    transferResult = session.GetFiles(p.RemotePath, p.LocalPath, p.IsRemoveSourceFile, transferOptions);

                    // Throw on any error
                    transferResult.Check();

                    //foreach (TransferEventArgs transfer in transferResult.Transfers)
                    //{

                    //}

                    rtn.IsSuccess = true;
                }
            }
            catch (Exception ex)
            {
                rtn.IsSuccess = false;
                rtn.ErrorMessage = ex.Message;
                throw ex;
            }
            return rtn;
        }
        /// <summary>
        /// 獲取指定遠端目錄下所有的文件，不含子目錄中的文件
        /// </summary>
        /// <param name="p">SFTPParameter</param>
        /// <returns>SFTPRtn</returns>
        public SFTPRtn ListFiles(SFTPParameter p)
        {
            SFTPRtn rtn = new SFTPRtn();
            try
            {
                SessionOptions sops = InitParameter(p);
                using (Session session = new Session())
                {
                    session.ExecutablePath = string.IsNullOrEmpty(p.WinscpExePath) ? null : p.WinscpExePath;
                    // Connect
                    session.Open(sops);

                    // Upload files
                    TransferOptions transferOptions = new TransferOptions();
                    transferOptions.TransferMode = p.TransferMode;
                    RemoteDirectoryInfo rdi;
                    rdi = session.ListDirectory(p.RemotePath);
                    rtn.ListFiles = new List<string>();
                    foreach (RemoteFileInfo rfi in rdi.Files)
                    {
                        if (!rfi.IsDirectory)
                        {
                            rtn.ListFiles.Add(rfi.Name);
                        }
                    }

                    rtn.IsSuccess = true;
                }
            }
            catch (Exception ex)
            {
                rtn.IsSuccess = false;
                rtn.ErrorMessage = ex.Message;
                throw ex;
            }
            return rtn;
        }

        /// <summary>
        /// 獲取指定遠端目錄下的所有子目錄，不含嵌套目錄
        /// </summary>
        /// <param name="p">SFTPParameter</param>
        /// <returns>SFTPRtn</returns>
        public SFTPRtn ListDirectories(SFTPParameter p)
        {
            SFTPRtn rtn = new SFTPRtn();
            try
            {
                SessionOptions sops = InitParameter(p);
                using (Session session = new Session())
                {
                    session.ExecutablePath = string.IsNullOrEmpty(p.WinscpExePath) ? null : p.WinscpExePath;
                    // Connect
                    session.Open(sops);

                    // Upload files
                    TransferOptions transferOptions = new TransferOptions();
                    transferOptions.TransferMode = p.TransferMode;
                    RemoteDirectoryInfo rdi;
                    rdi = session.ListDirectory(p.RemotePath);
                    rtn.ListDirectories = new List<string>();
                    foreach (RemoteFileInfo rfi in rdi.Files)
                    {
                        if (rfi.IsDirectory)
                        {
                            rtn.ListDirectories.Add(rfi.Name);
                        }
                    }

                    rtn.IsSuccess = true;
                }
            }
            catch (Exception ex)
            {
                rtn.IsSuccess = false;
                rtn.ErrorMessage = ex.Message;
                throw ex;
            }
            return rtn;
        }

        private SessionOptions InitParameter(SFTPParameter p)
        {
            SessionOptions sessionOptions = new SessionOptions
            {
                Protocol = p.Protocol,
                HostName = p.HostName,
                UserName = p.UserName,
                Password = p.Password,
                SshHostKey = p.SSHHostKey
            };
            sessionOptions.PortNumber = p.ServerPort;
            return sessionOptions;
        }
    }
}
